/*
* CurrencyDecimalPlaceUtil.java
*
* Created on 2005��7��1��, ����4:33
* All rights reserved. All information contained in this software is
* confidential and proprietary to Pacific Century Cyberworks. No part of this
* software may be reproduced or transmitted in any form or any means,
* electronic, mechanical, photocopying, recording or otherwise stored in any
* retrieval system of any nature without the prior written permission of
* Pacific Century Cyberworks.
*
* This material is a trade secret and its confidentiality is strictly
* maintained. Use of any copyright notice does not imply unrestricted public
* access to this material.
*
* (c) Pacific Century Cyberworks
*/

package com.fruit.utils;

import java.math.BigDecimal;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.fruit.web.constant.EjdConstants;


/**
 *
 * @author Forrest Chen
 */
public class CurrencyDecimalPlaceUtil {

    private static final String intFormat = "#,##0";
    private static final Map map = new HashMap();
    private static boolean initFlag = false;
    static DecimalFormat amtFormatter = new DecimalFormat("0.00");
    static DecimalFormat unitrateFormatter = new DecimalFormat("0.000");

    public static final int NO_ADJUSTMENT_DECIMAL_PLACE = 2;
    public static final int DECIMAL_PLACE_FOR_CALC = 6;
    public static final String AMOUNT_FORMAT = "0.00";
    public static final NumberFormat AMOUNT_FORMATTER = new DecimalFormat(AMOUNT_FORMAT);
    private static final String sImplement = "00000000000000";


    /** Creates a new instance of CurrencyDecimalPlaceUtil */
    private CurrencyDecimalPlaceUtil() {
    }

    private static void initCurrencyDecimalPlaceUtil() throws Exception
    {
      
    }

    public static int getCurrencyDecimalPlace(String currencyCode)throws Exception
    {
        initCurrencyDecimalPlaceUtil();
        Integer decimalPlace = (Integer)map.get(currencyCode);
        if(decimalPlace==null)
            return 0;
        return decimalPlace.intValue();
    }

    public static String getCurrencyDecimalPlaceFormat(String currencyCode)throws Exception
    {
        int decimalPlace = getCurrencyDecimalPlace(currencyCode);
        if(decimalPlace<=0)
            return intFormat;

        int initValue = 10^decimalPlace;
        return intFormat+"."+String.valueOf(initValue).substring(1);
    }

    public static double trunc(double d, int decimalPlace) {

        //long l = (long)(d * Math.pow(10,decimalPlace));
        long l = (long)(Math.round(d * Math.pow(10,decimalPlace)));
        d = (double)(l/Math.pow(10,decimalPlace));

        return d;
    }

    public static double round(double d, int decimalPlace) {

        //System.out.println(" before rounding === " + d);
        boolean isNegative = d < 0;
        if(isNegative) {
            d=d*-1;
        }
        double round = Math.pow(10, decimalPlace);
        double adjustment = 1d/(Math.pow(10, 10));
        d = d + adjustment;
        //System.out.println(" in round method, d ==== " + d);
        long l = Math.round(d * round);
        //System.out.println(" in round method, l ==== " + l);
        d = l/round;

        if(isNegative) {
            return d*-1d;
        }
        return d;
    }
    
    
    public static double round(double d, int decimalPlace, String roundingMethod) {
    	double pow = Math.pow(10, decimalPlace);
    	double value = pow * d;
    	roundingMethod = CommonUtil.isEmptyStr(roundingMethod) ? EjdConstants.ROUNDING_METHOD_NORMAL : roundingMethod;
    	if (EjdConstants.ROUNDING_METHOD_NORMAL.equals(roundingMethod)) {
    		return Math.round(value)/pow;
    	} else if (EjdConstants.ROUNDING_METHOD_UP.equals(roundingMethod)) {
    		return Math.ceil(value)/pow;
    	} else {
    		return Math.floor(value)/pow; 
    	}
    }
    

    public static double round(double originalValue){
        int decimalPlace = 2;
        return round(originalValue, decimalPlace);
    }

    static public String formatAmtGeneral(double d) {

        return formatAmt(d, 0, 2);
    }

    static public String formatAmt(double d, double adjustment, int decimalPlace) {
        int ignoreDigit = 8;

        int negativefactor = d>0?1:-1;

        adjustment = adjustment * negativefactor;

        double diff = trunc(d,ignoreDigit) - trunc(d,decimalPlace);
        
        System.out.println("round str:" + Double.toString(trunc(d,ignoreDigit)));
        System.out.println("trunc str:" + Double.toString(trunc(d,decimalPlace)));
        
        
        
        Double.toString(trunc(d,decimalPlace));

         System.out.println("round:" + trunc(d,ignoreDigit));
         System.out.println("trunc:" + trunc(d,decimalPlace));

         System.out.println("diff:" + diff);


        System.out.println("round(Math.abs(diff),3) ===  "+ round(Math.abs(diff),3));
        
        

        // if (round(Math.abs(diff),3) >= 0.005)
        if (!Double.toString(trunc(d,ignoreDigit)).equals(Double.toString(trunc(d,decimalPlace))))
            d = round(d + adjustment, decimalPlace);
        else
            d = round(d, decimalPlace);
        //System.out.println("d ======= " + d);
        return amtFormatter.format(d);

    }
    
    public static BigDecimal round(BigDecimal number, int nrOfDecimalPlace) {
        if (number == null) {
            return null;
        } else {
            return new BigDecimal(round(number.doubleValue(), nrOfDecimalPlace));
        }
    }

    static public double getFormatAmt(double d, double adjustment, int decimalPlace) {

        String s = formatAmt(d, adjustment, decimalPlace);

        return Double.parseDouble(s);

    }
    
    static public String formatUnitRate(double d) {

        return unitrateFormatter.format(round(d,3));
    }

    static public double parseDouble(String doubleString, String format) throws Exception{
        DecimalFormat formatter = new DecimalFormat(format);
        return formatter.parse(doubleString).doubleValue();
    }


    // Added By Penny to unique amount rounding
    public static double roundedNoAdjustAmount( double originalValue ){
        double adjustment = 0;
        int decimalPlace = 2;
        return Double.parseDouble(formatAmt(originalValue, adjustment, decimalPlace));
    }

    public static double roundedAdjustAmount (double originalValue, int decimalPlace, double adjustment){
        return Double.parseDouble(formatAmt(originalValue, adjustment, decimalPlace));
    }
    //  Added By David 
    public static double roundedNoAdjustAmount( double originalValue,int decimalPlace ){       
        return round(originalValue,decimalPlace);
    }
   //  Added By David
    public static double roundedExchangeRate(double originalValue,int decimalPlace) {
       return round(originalValue, decimalPlace);
    }

    static public String formatInvAmt(double d, double adjustment, int decimalPlace) {
        String value=String.valueOf(d)+sImplement;         
        int pos=value.indexOf(".");
        if(pos!=-1){
        	String temp=value.substring(pos+decimalPlace+1,pos+decimalPlace+2);     	
        	if(temp!=null&&!"".equals(temp)&&!temp.equals("0")){
        		d+=adjustment;
        	}        	
        }      
        d = round(d, decimalPlace); 
        return amtFormatter.format(d);

    }
    
    
    static public String formatInvAmt1(double d, double adjustment, int decimalPlace) {
        String value=String.valueOf(d)+sImplement;         
        int pos=value.indexOf(".");
        if(pos!=-1){
        	String temp=value.substring(pos+decimalPlace+1,pos+decimalPlace+2);        	
        	if(temp!=null&&!"".equals(temp)&&!temp.equals("0")){
        	}        	
        }  
        return String.valueOf(d);
    }
    
    static public String formatAmt(double d) {       
        return amtFormatter.format(d);
    }
    static public String formatAmt(double d,int decimalPlace) {  
    	String amoutFormatStr="#,##0.00";
    	String formatLef="";
    	for(int i=0;i<decimalPlace;i++){
    		formatLef+="0";    		
    	}
    	if(!"".equals(formatLef)){
    		amoutFormatStr="#,##0."+formatLef;
    	}
    	NumberFormat amountFormat = new DecimalFormat(amoutFormatStr);     	
        return amountFormat.format(d);
    }
    /* desc:add formatAmt2()
     * add format defalut #,##0
     * S20090205 James.huang add
     */
    static public String formatAmt2(double d,int decimalPlace) {  
    	String amoutFormatStr="#,##0";
    	String formatLef="";
    	for(int i=0;i<decimalPlace;i++){
    		formatLef+="0";    		
    	}
    	if(!"".equals(formatLef)){
    		amoutFormatStr="#,##0."+formatLef;
    	}
    	NumberFormat amountFormat = new DecimalFormat(amoutFormatStr);     	
        return amountFormat.format(d);
    }
    /* desc:add formatAmt2()
     * add format defalut #,##0
     * E20090205 James.huang add
     */
    //S20090331 James.huang 3104 format #,###.0000
    static public String formatAmt3(double d) {  
    	String amoutFormatStr="#,###.0000";
    	NumberFormat amountFormat = new DecimalFormat(amoutFormatStr);     	
        return amountFormat.format(d);
    }
    //E20090331 James.huang 3104 format #,###.0000
   public static String getNumberFormatString(int decimalPlace) {  
    	 String formatString = "#,##0";
    	 if(decimalPlace > 0){
    		 formatString += ".0";
    		 for(int i=1; i<decimalPlace; i++){
    			 formatString += "0";
    			 }
    		 }
    	 return formatString;
    }
   
   //add by zhyd currency setting
   public static double calculateRoundingAmount(double value, double decimalPlace, String roundingMethod){
	   //S Vinco.Weng 2009-3-27 -value roundmethod
	   boolean isNegative = value < 0;
       if(isNegative){
    	   value = value*(-1);
       }	   
       if(roundingMethod==null){
    	   roundingMethod = "N";
       }
	   //E Vinco.Weng 2009-3-27
		double pow = Math.pow(10, decimalPlace);			
		double temp = Math.round(value*pow)/pow;
		if(value!=temp){
			double adjustment = 0;
			if(roundingMethod.equals("U")){
				adjustment = 0.5/pow;
			}
			else if(roundingMethod.equals("D")){
				adjustment = -0.5/pow;
			}
			value = value + adjustment;
			value = Math.round(value*pow)/pow;
		}
		//S Vinco.Weng 2009-3-27 -value roundmethod
		if(isNegative){
			value = value*(-1);
		}
        //E Vinco.Weng 2009-3-27
		return value;		
	}
   //end add
   
	// see FS for Bug 1711
	private static final String ROUND_UP_TO_THE_NEAREST_HALF = "CT_ROUNDING_1";
	private static final String DROP_ALL_UNDER_DECIMAL_POINT = "CT_ROUNDING_2";
	private static final String ROUND_UP_TO_THE_NEAREST_FIVE = "CT_ROUNDING_3";
	private static final String ROUND_DOWN_TO_THE_NEAREST_TEN = "CT_ROUNDING_4";
	
	// rounding mode
	private static final byte NORMAL_MODE = 0x00;
	private static final byte ROUND_UP_MODE = 0x01;
	private static final byte ROUND_DOWN_MODE = 0x02;
	
	// for the 4 rounding methods in Bug 1711
	public static double round (double value, String roundingMethod)
	{
		// assume that number is positive
		if (value < 0)
			throw new ArithmeticException("The number to be rounded is expected to be positive. Number = "+value);
		
		if(roundingMethod!=null) {
			if (roundingMethod.equals(ROUND_UP_TO_THE_NEAREST_HALF))		// round up to the nearest 50 cents
				return round(value, ROUND_UP_MODE, 0.5);
			else if (roundingMethod.equals(DROP_ALL_UNDER_DECIMAL_POINT))	// truncate all decimal. (round down to the nearest integer)
				return Math.floor(value);
			else if (roundingMethod.equals(ROUND_UP_TO_THE_NEAREST_FIVE))	// round up to the nearest 5 dollar
				return round(value, ROUND_UP_MODE, 5);
			else if (roundingMethod.equals(ROUND_DOWN_TO_THE_NEAREST_TEN))	// round down to the nearest 10 dollar
				return round(value, ROUND_DOWN_MODE, 10);
			else
				throw new IllegalArgumentException("Invalid rounding method: "+roundingMethod);
		}
		return value;
	}
	
	// a generic rounding method
	// step=1 for round to the nearest integer, step=0.01 for rounding to 2 d.p., step=0.75 for rounding to the nearest multiple of 0.75, etc.
	private static double round(double value, byte mode, double step)
	{
		switch (mode)
		{
		case ROUND_UP_MODE:
			return Math.ceil(value/step)*step;
		case ROUND_DOWN_MODE:
			return Math.floor(value/step)*step;
		case NORMAL_MODE:
		default:
			return Math.round(value/step)*step;
		}
	}
   
    public static void main(String[] args){
        System.out.println(round(19.1849d, 2));
        System.out.println(calculateRoundingAmount(-12.495, 2,"N"));
        System.out.println(round(-12.495, 2));
        System.out.println(round(19.1845d, 4));
        System.out.println(round(19.18454d, 4));
//
//        double d1 = 1333333.31499999999999999999999999;
//        double d2 = 1333333.315000000000000000000009;
//        double d3 = 1333333.6048999999999999999999999;
//        double d4 = 1333333.6050000000000000000000001;
//
//        System.out.println(" 25*1.105 === " + roundedNoAdjustAmount(25*1.105));
//        System.out.println(" -25*1.105 === " + roundedNoAdjustAmount(-25*1.105));
//
//        System.out.println(" 2.085*127 === " + roundedNoAdjustAmount(2.085*127));
//        System.out.println(" -2.085*127 === " + roundedNoAdjustAmount(-2.085*127));
//
//        System.out.println(" 1.71*92  ============= " + roundedAdjustAmount(1.72*91, 1, 0.05));
//        System.out.println(" 1.311*459 ============= " + roundedAdjustAmount(1.311*459, 1, 0.05));
//
//        System.out.println(" 2.085*127 === " + roundedNoAdjustAmount(2.085*127));
//        System.out.println(" 2.085*127 === " + roundedNoAdjustAmount(-2.085*127));
//        System.out.println(" 25*5.917    ============= " + roundedNoAdjustAmount(25*5.917));
//        System.out.println(" -25*5.917    ============= " + roundedNoAdjustAmount(-25*5.917));
//        System.out.println(" d4 ============= " + roundedNoAdjustAmount(d4*1));

    }

}
